package com.study.util;


import java.lang.reflect.Field;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;


/**CRUD是指在对数据处理时的增加(Create)、
 * 读取查询(Retrieve)、
 * 更新(Update)、
 * 删除(Delete)几个单词的首字母简写。
 * CRUD主要被用在描述数据库或者持久层的基本操作功能。
 * @author SMILE
 * @param <T>  
 *  泛型（不确定具体的实体类型，所以此处用T来代替）
 */
public class CRUDBaseDAO<T> extends DBUtils{
	private Connection conn=null;
	private PreparedStatement stmt=null;
	private ResultSet rs=null;
	private Class<T> entity_class;
	
	/**带参构造方法
	 * 传递实体类的类型如：Shopping.class
	 * @param entity_class  类名.class
	 */
	public CRUDBaseDAO(Class<T> c){
		this.entity_class=c;
	}
	/**执行增删改操作
	 * @param sql  要执行的SQL语句
	 * @param o    占位符需要的参数，以数组的形式传递过来
	 * @return	        返回受影响的行数
	 * @throws Exception	抛出了异常，谁调用谁处理
	 */
	protected int update(String sql,Object[] o) {
		try {
			//获取父类的连接对象
			conn=super.getConnection();
			//预编译执行对象
			stmt=conn.prepareStatement(sql);
			//将占位符的参数添加到prepareStatement当中去
			addStatementParam(o);
			System.out.println("增删改SQL语句："+stmt.toString());
			//返回执行的结果
			return stmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			super.close(conn, stmt,null);
		}
		
		return 0;
	}

	/**执行查询结果，并返回集合
	 * @param sql	要执行的SQL语句
	 * @param pram	占位符需要的参数，以数组的形式传递过来
	 * @return		
	 */
	protected List<T> query(String sql,Object[] pram){
		List<T> list=new ArrayList<T>();
		try {
			//获取父类的连接对象
			conn=super.getConnection();
			//预编译执行对象
			stmt=conn.prepareStatement(sql);
			//将占位符的参数添加到prepareStatement当中去
			addStatementParam(pram);

			System.out.println("查询SQL语句："+stmt.toString());
			//返回执行的查询结果

			System.out.println("查询结果是："+stmt.toString());
			

			rs=stmt.executeQuery();
			while(rs.next()){
				list.add(toEntity());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			super.close(conn, stmt, rs);
		}
		return list;
	}
	
	/**执行新增操作
	 * @param sql  要执行的SQL语句
	 * @param o    占位符需要的参数，以数组的形式传递过来
	 * @return	       返回新增的主键ID
	 * @throws Exception	抛出了异常，谁调用谁处理
	 */
	protected int insert(String sql,Object[] o){
		int newId=0;
		try {
			//获取父类的连接对象
			conn=super.getConnection();
			//预编译执行对象
			stmt=conn.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);
			//将占位符的参数添加到prepareStatement当中去
			addStatementParam(o);
			System.out.println("新增SQL语句："+stmt.toString());
			//执行的结果
			int i= stmt.executeUpdate();
			if(i>0) {
				rs=stmt.getGeneratedKeys();
				rs.next();
				newId=rs.getInt(1);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			super.close(conn, stmt, rs);
		}
		return newId;
	}
	
	/**获取总数
	 * @param sql
	 * @param o
	 * @return
	 */
	protected Integer getTotal(String sql,Object[] o) {
		int count=0;
		try {
			//获取父类的连接对象
			conn=super.getConnection();
			//预编译执行对象
			stmt=conn.prepareStatement(sql);
			//将占位符的参数添加到prepareStatement当中去
			addStatementParam(o);
			System.out.println("统计SQL语句："+stmt.toString());
			rs = stmt.executeQuery();
			if(rs!=null && rs.next()) {
				count = rs.getInt(1);
			}
		} catch (Exception e) {
			count=0;
		}finally {
			super.close(conn, stmt, rs);
		}
		return count;
	}
	
	
	/**返回查询的单个实体对象
	 * @param sql
	 * @param param
	 * @return
	 */
	protected T getOne(String sql,Object[] param) {
		List<T> list = query(sql, param);
		if(list!=null && list.size()>0) {
			return list.get(0);
		}
		return null;
	}
	
	
	
	/**执行存储过程
	 * @param sql	{call abc(?,?)}
	 * @param param
	 * @return
	 */
	protected int excuteProcudure(String sql,Object[] param) {
		int result=0;
		//声明CallableStatement对象
        CallableStatement proc=null;
        try {
        	//获取父类的连接对象
			 conn=super.getConnection();
        	 proc=conn.prepareCall(sql);
        	 if(param!=null) {
        		 int i=1;
        		 for (Object o : param) {
					proc.setObject(i, o);
					i++;
				}
        	 }
        	 System.out.println("存储过程执行结果："+proc);
        	 boolean opin=proc.execute();
        	 result=opin?1:0;;
		} catch (Exception e) {
			e.printStackTrace();
			result=-1;
		}finally {
			close(conn, proc, null);
		}
        return result;
	}
	
	/**利用反射将数据集的数据添加到实体类当中
	 * @return  返回实体类的对象
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws SQLException
	 */
	private T toEntity() throws InstantiationException, IllegalAccessException, SQLException {
		T entity=null;
		entity=entity_class.newInstance();
		Field fie[]=entity_class.getDeclaredFields();
		//获得结果集的信息
		java.sql.ResultSetMetaData rsmd=rs.getMetaData();
		for (Field field : fie) {
			
			//双重循环比较反射的字段与结果集的列名是否一致
			for (int i = 1; i <= rsmd.getColumnCount(); i++) {
				//获得反射类的字段名和结果集的列名
				String fieldName=field.getName();

				String rsName=rsmd.getColumnLabel(i);//获取的是别名

				
				
			
				

				if(fieldName.toLowerCase().equals(rsName.toLowerCase())){
					field.setAccessible(true);
					Object o=rs.getObject(rsName);
					field.set(entity,o);
					break;
				}
			}
		}
		return entity;
	}
	
	/**将占位符的参数添加到prepareStatement对象当中去
	 * @param o		一维数组参数
	 * @throws SQLException 抛出了异常，谁调用谁处理
	 */
	private void addStatementParam(Object[] o) throws SQLException {
		if(o!=null){
			for (int i = 0; i < o.length; i++) {
				stmt.setObject(i+1, o[i]);
			}
		}
	}
}
